home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / AHDI / SYQUEST / SQHDX / MARKBAD.C < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-09  |  35.0 KB  |  1,214 lines

  1. /* markbad.c */
  2.  
  3. /* 18-Apr-88  ml.    implement delete of trashed subdirectory with       */
  4. /*            recovering of files.                   */
  5. /* 16-Mar-88  ml.    split assist.c into this and zero.c.           */
  6. /* 15-Mar-88  ml.    allow user to determine destiny of trashed files.  */
  7. /* 16-Oct-87  ml.    fixed some bugs.                   */
  8. /* 26-Oct-87  ml.    rewrote markbad, readrange, fixbadcls (everything).*/
  9. /* 28-Oct-87  ml.    modified markbad to mark fats and root dir also.   */
  10. /* 11-Dec-87  ml.    added BSL concept to markbad() and zero().       */
  11.  
  12. #include "obdefs.h"
  13. #include "gemdefs.h"
  14. #include "osbind.h"
  15. #include "defs.h"
  16. #include "part.h"
  17. #include "bsl.h"
  18. #include "getstart.h"
  19. #include "hdx.h"
  20. #include "addr.h"
  21.  
  22. extern long addbsl();
  23. extern long gbslsiz();
  24. extern long nument();
  25. extern long cntbad();
  26. extern int *fatck();
  27. extern GSINFO *getstart();
  28.  
  29. extern long bslsiz;
  30. extern BYTE *bsl;
  31. extern SECTOR badbuf[];        /* bad sectors buffer */
  32.  
  33. UWORD ndirs;    /* total number of root directory entries */
  34. UWORD sectdir;    /* number of sectors root directory entries take up */
  35. UWORD clusiz;    /* number of bytes per cluster */
  36. SECTOR strootdir;    /* starting sector number of root directory */
  37. int endofdir;        /* TRUE: reaches end of directory */
  38.  
  39. long badmarkd;        /* number of bad sectors actually marked */
  40. int emptyorph=0;    /* an empty orphan list */
  41. GSINFO    *finfo;        /* file information from getstart() */
  42.  
  43. extern int gl_wchar;    /* width of system font (pixels) */
  44. char pname[260];    /* full path name of a file */
  45. char dpname[260];    /* full path name of a file to be displayed */
  46. char sectbuf[10];
  47. char clusbuf[10];
  48.  
  49.  
  50. /*
  51.  * Mark bad sectors on the logical dev
  52.  *
  53.  */
  54. markbad(ldev)
  55. int ldev;
  56. {
  57.     SECTOR fat0, fat1, data, dummy = 0L;
  58.     long nsects, readfix();
  59.     UWORD sect2read, fatsiz, w1, w2;
  60.     long nbad;
  61.     char bs[512], foundbuf[10], markdbuf[10];
  62.     BOOT *boot;
  63.     int pdev, ret;
  64.  
  65.     
  66.     pdev = ldev;
  67.     log2phys(&pdev, &dummy);
  68.     
  69.     /* Allocate memory for BSL and try to read it */ 
  70.     bsl = 0L;
  71.     if ((bslsiz = gbslsiz(pdev)) > 0L) {
  72.         if ((bsl = (BYTE *)mymalloc((int)bslsiz*512)) <= 0)
  73.             return err(nomemory);
  74.             
  75.         if ((dummy = rdbsl(pdev)) != OK) {
  76.             free(bsl);
  77.             if (dummy == INVALID)
  78.                 err(cruptbsl);
  79.             return ERROR;
  80.         }
  81.     } else if (bslsiz < 0L){
  82.     if (bslsiz == ERROR)
  83.         err(rootread);
  84.     return ERROR;
  85.     }
  86.  
  87.     /*
  88.      * Read boot sector and extract volume information.
  89.      */
  90.     if ((ret = rdsects(ldev, 1, bs, (SECTOR)0)) != 0) {
  91.         free(bsl);
  92.         if (tsterr(ret) != OK)
  93.             err(bootread);
  94.         return ERROR;
  95.     }
  96.  
  97.     boot = (BOOT *)bs;
  98.      
  99.     gw((UWORD *)&boot->b_ndirs[0], &ndirs);
  100.     gw((UWORD *)&boot->b_spf[0], &fatsiz);
  101.     gw((UWORD *)&boot->b_res[0], &w1);
  102.     gw((UWORD *)&boot->b_nsects[0], &w2);
  103.     clusiz = boot->b_spc * 512;
  104.     fat0 = (SECTOR)w1;
  105.     fat1 = fat0 + (SECTOR)fatsiz;
  106.     strootdir = fat1 + fatsiz;
  107.     sectdir = (ndirs * 32) / 512;
  108.     data = (SECTOR)(strootdir + sectdir);
  109.     nsects = (SECTOR)w2;
  110.     sect2read = (UWORD)(nsects - data);
  111.  
  112.     /* Marking bad */
  113.     if ((nbad = readfix(ldev, data, fat0, fatsiz, sect2read)) < 0) {
  114.         if (bsl > 0) free(bsl);
  115.         return ERROR;
  116.     }
  117.  
  118.     /* Bad sectors found, BSL modified.  Write it back. */
  119.     if (nbad) {
  120.         if (bslsiz)
  121.             if (wrbsl(pdev) != OK) {
  122.                 free(bsl);
  123.                 return ERROR;
  124.             }
  125.     }
  126.     if (bsl > 0) free(bsl);        
  127.     
  128.     /* Display result of markbad */
  129.     ltoa(nbad, foundbuf);
  130.     ltoa(badmarkd, markdbuf);
  131.     (lmrkdone[BADFOUND].ob_spec)->te_ptext = foundbuf;
  132.     (lmrkdone[BADMARKD].ob_spec)->te_ptext = markdbuf;
  133.     lmrkdone[LMDONE].ob_state = NORMAL;
  134.     erasemsg();
  135.     execform(lmrkdone);
  136.     return OK;
  137. }
  138.  
  139.  
  140.   
  141. /* 
  142.  * Critical Error Handler:
  143.  *    Always return -1L
  144.  *
  145.  */
  146. long
  147. crerr()
  148. {
  149.     return -1L;
  150. }
  151.  
  152.  
  153.  
  154. /*
  155.  * Read range of sectors,
  156.  * record bad ones in the vector,
  157.  * add bad sectors found to the BSL,
  158.  * mark bad sectors in the FATs,
  159.  * return number of bad ones.
  160.  *
  161.  */
  162. long 
  163. readfix(ldev, data, fat0, fatsiz, sect2read)
  164. int ldev;        /* logical device to read from */
  165. SECTOR data;        /* LSN of first sector of data clusters */
  166. SECTOR fat0;        /* LSN of first sector of FAT 0 */
  167. UWORD fatsiz;        /* size of FAT in sectors */
  168. UWORD sect2read;    /* number of sectors to read */
  169. {
  170.     int nbad=0, full=0;
  171.     int pdev;        /* physical device number */
  172.     SECTOR pstart;    /* physical starting block# of partition */
  173.     SECTOR pdata;    /* physical starting block# of data clusters */
  174.     UWORD cnt, cnt1;
  175.     extern SECTOR logstart();
  176.     char *rbuf = 0L;        /* read buffer */
  177.     long ret = 0L, totbad;
  178.     long dummy = 0L;
  179.  
  180.     pdev = ldev;
  181.     log2phys(&pdev, &dummy);
  182.     pstart = logstart(ldev);
  183.  
  184.     /* Allocate memory for read buffer */
  185.     if ((rbuf = (char *)Malloc((long)(MAXSECTS << 9))) <= 0) {
  186.         ret = err(nomemory);
  187.         goto readend;
  188.     }
  189.         
  190.     /*
  191.      * Read lots of sectors, MAXSECTS sectors at a time;
  192.      * if an error happens, then probe individual sectors
  193.      * in the lump of MAXSECTS that failed.
  194.      */
  195.  
  196.     totbad = 0L;
  197.     badmarkd= 0L;
  198.     pdata = pstart + data;
  199.     while (sect2read > 0) {
  200.     if (sect2read > MAXSECTS)
  201.         cnt = MAXSECTS;
  202.     else
  203.         cnt = sect2read;
  204.  
  205.     if ((ret = rdsects(pdev, cnt, rbuf, pdata)) != 0) {
  206.         if (tsterr(ret) == OK) {
  207.             ret = ERROR;
  208.             goto readend;
  209.         }
  210.         cnt1 = cnt;
  211.         while (cnt1) {
  212.             if ((ret = rdsects(pdev, 1, rbuf, pdata)) != 0) {
  213.                 if (tsterr(ret) == OK) {
  214.                     ret = ERROR;
  215.                     goto readend;
  216.                 }
  217.             badbuf[nbad++] = pdata;
  218.             
  219.             /* badbuf is filled */
  220.             if (nbad == WARNBADSECTS) {
  221.                 if (bslsiz && !full)    /* USER list is not full yet */
  222.                     /* try to add bad sectors found to BSL */
  223.                     if ((ret = addbsl(pdev, USER, nbad)) < 0) {
  224.                         if (ret == USRFULL)
  225.                             full = 1;
  226.                         else {
  227.                             ret = ERROR;
  228.                             goto readend;
  229.                         }
  230.                     } else if (ret > 0) {
  231.                 if (wrbsl(pdev) != 0) {
  232.                     ret = ERROR;
  233.                     goto readend;
  234.                 }
  235.                 }
  236.                 
  237.                 /* mark the bad sectors in the FATs */
  238.                 if ((ret = fixbadcls(ldev, fat0, fatsiz, 
  239.                     data, nbad)) < 0) {
  240.                 goto readend;
  241.                 }
  242.                 badmarkd += ret;
  243.                 totbad += nbad;
  244.                 nbad = 0;    /* reinit bad sectors count to 0 */
  245.             }
  246.                                         
  247.             }
  248.         cnt1--;
  249.         pdata++;
  250.         }
  251.     } else {
  252.         pdata += cnt;
  253.     }
  254.     sect2read -= cnt;
  255.     }
  256.     
  257.     if (nbad) {    /* bad sectors found but not recorded in BSL or FATs */
  258.         if (bslsiz && !full)    /* USER list is not full yet */
  259.             /* try to add bad sectors found to BSL */
  260.             if ((ret = addbsl(pdev, USER, nbad)) < 0) {
  261.                 if (ret == USRFULL)
  262.                     full = 1;
  263.                 else {
  264.                     ret = ERROR;
  265.                     goto readend;
  266.                 }
  267.             } else if (ret > 0) {
  268.         if (wrbsl(pdev) != 0) {
  269.             ret = ERROR;
  270.             goto readend;
  271.         }
  272.         }                
  273.         
  274.         /* mark the bad sectors in the FATs in terms of clusters */
  275.         if ((ret = fixbadcls(ldev, fat0, fatsiz, data, nbad)) < 0) {
  276.         goto readend;
  277.         }
  278.         badmarkd += ret;        
  279.         totbad += nbad;
  280.     }
  281.     ret = totbad;
  282.     
  283. readend:
  284.     if (rbuf > 0) Mfree(rbuf);    
  285.     return (ret);
  286. }
  287.  
  288.  
  289.  
  290. /*
  291.  * Fixup bad sector entries in the FATs;
  292.  * suboptimal, since a FAT sector is read and two are
  293.  * written for EACH bad sector, even if there is
  294.  * more than one bad entry in a given FAT sector.
  295.  *
  296.  *
  297.  */
  298. fixbadcls(ldev, fat0, fatsiz, data, nbad)
  299. int ldev;        /* logical device */
  300. SECTOR fat0, data;
  301. UWORD fatsiz;
  302. int nbad;
  303. {
  304.     long numcl;
  305.     UWORD clno, nxtcl;
  306.     int i;
  307.     UWORD *buf;
  308.     SECTOR fat1;    /* physical starting sector# of 2nd FAT */
  309.     SECTOR pstart;    /* physical starting sector# of partition */
  310.     SECTOR badsect;    /* current bad sector */
  311.     extern SECTOR logstart();
  312.     extern LOGMAP logmap[];
  313.     int did=0, nmarked, ret, spc;
  314.     
  315.     
  316.     if((buf = (UWORD *)Malloc((long)fatsiz*512)) <= 0)
  317.         return err(nomemory);
  318.     pstart = logstart(ldev);
  319.  
  320.     if (logmap[ldev-'C'].lm_siz >= 0x8000L)    /* partition >= 16Mb */
  321.         spc = 4;                /* Yes, 4 spc */
  322.     else
  323.         spc = 2;                    /* No, 2 spc */
  324.     numcl = (logmap[ldev-'C'].lm_siz - data) / spc;
  325.     
  326.     fat1 = fat0 + fatsiz;
  327.             
  328.     if ((ret = rdsects(ldev, fatsiz, (char *)buf, fat0)) != 0) {
  329.         if (tsterr(ret) != OK)
  330.         err(fatread);
  331.     ret = ERROR;
  332.     goto fixend;
  333.     }
  334.     nmarked = 0;
  335.     for (i = 0; i < nbad; ++i) {
  336.     badsect = badbuf[i] - pstart;
  337.     if ((clno = (badsect - data) / spc) >= numcl)
  338.         continue;
  339.             
  340.         /* find out the next cluster number */
  341.         gw((UWORD *)(buf+clno+2), &nxtcl);
  342.             
  343.     /* part of file?? */
  344.         if (nxtcl != 0 && (nxtcl <= 0x7fff || nxtcl >= 0xfff8))    {
  345.             /* Yes, bummer */
  346.             if ((ret = partoffile(ldev, buf, fatsiz, badsect, clno, nxtcl))
  347.                     < 0)
  348.                 goto fixend;
  349.             nmarked += ret;
  350.     } else {    /* just mark it bad */
  351.         /* Nope, ah ha, just mark it bad */
  352.         *(buf+clno+2) = 0xf7ff;    /* 0xfff7 in 8086-land */
  353.         nmarked++;
  354.     }
  355.  
  356.     /* write FAT0 and FAT1 */
  357.     if ((ret = wrsects(ldev, fatsiz, (char *)buf, fat0)) != 0 ||
  358.         (ret = wrsects(ldev, fatsiz, (char *)buf, fat1)) != 0)
  359.     {
  360.         if (tsterr(ret) != OK)
  361.             err(fatwrite);
  362.         ret = ERROR;
  363.         goto fixend;
  364.     }
  365.     }
  366.     ret = nmarked;
  367. fixend:
  368.     Mfree((long)buf);
  369.     return ret;
  370. }
  371.  
  372.  
  373. /*
  374.  *  Handle situations when bad sector found is currently allocated
  375.  *  to a file.
  376.  *
  377.  *    Options for user:
  378.  *        - Delete the victim file. (Lose all data in file.)
  379.  *          Bad sector will be marked in FATs.
  380.  *        - Skip over the cluster where the bad sector resides.
  381.  *          (Lose data in bad sector only.)  Need to patch up
  382.  *          FATs and root directory entry of file.  Bad sector
  383.  *          will be marked in FATs.
  384.  *        - Ignore the bad sector. Bad sector will stay unmarked
  385.  *          in FATs.
  386.  *
  387.  *    Input:
  388.  *        ldev - logical device.
  389.  *        fatimg - image of FAT table.
  390.  *        fatsiz - # clusters FAT occupies.
  391.  *        badsect - bad sector in question.
  392.  *        clno - cluster containing the bad sector.
  393.  *        nxtcl - next cluster in chain. (ie. cluster currently
  394.  *            pointed to by cluster with the bad sector.
  395.  *
  396.  *    Output:
  397.  *        ERROR - if something went wrong in the process.
  398.  *        1 - cluster in question is marked.  Image of FATs 'may'
  399.  *            be modified, depending on the option chosen by the
  400.  *            user.
  401.  *
  402.  *    Comments:
  403.  *        Things get pretty hairy when the bad sector is allocated
  404.  *    to a subdirectory file (ie. file that contains entries of other
  405.  *    files belonging to that subdirectory).  As of today (17-Mar-88),
  406.  *    no action (may be an alert) will be taken for victim subdirectory
  407.  *    files.
  408.  *        31-Mar-88 : started to add routines to take care of
  409.  *    trashed subdirectories.
  410.  *        11-Apr-88 : froze development of relinking trashed
  411.  *    subdirectories.  Will fix all known bugs and release first.
  412.  *        18-Apr-88 : started to implement recovering of files of
  413.  *    a trashed subdirectory.
  414.  *
  415.  */
  416. partoffile(ldev, fatimg, fatsiz, badsect, clno, nxtcl)
  417. int ldev;            /* logical device number */
  418. UWORD *fatimg;            /* FAT's image */
  419. UWORD fatsiz;        /* #sectors in FAT */
  420. SECTOR badsect;            /* sector which is bad */
  421. UWORD clno, nxtcl;    /* current cluster # and next cluster # */
  422. {
  423.     int *orphans;        /* list of orphans in FAT */
  424.     UWORD numorph;        /* number of orphans found in FAT */
  425.     FCB *dirent;        /* a directory entry */
  426.     int attribs;        /* file attributes */
  427.     int ret;            /* return code */
  428.     int tail;            /* num pixels path name exceeds box's width */
  429.     int sub;            /* TRUE: file in process is a subdirectory */
  430.     int i;            /* index */
  431.     
  432.     ret = OK;    /* assume everything is OK to start with */
  433.     /* Check integrity of FATs */
  434.     if ((orphans = fatck(ldev-'A')) <= 0L) {
  435.     switch (orphans) {
  436.         case FFATS:
  437.         ret = err(fatread);
  438.         goto leave;
  439.         case FROOT:
  440.         ret = err(dirread);
  441.         goto leave;
  442.         case FFAIL:
  443.         ret = err(nomemory);
  444.         goto leave;
  445.         case FAMBI:
  446.         ret = err(badfat);
  447.         goto leave;
  448.         default:
  449.         break;
  450.     }
  451.     }
  452.  
  453.     ltoa(badsect, sectbuf);    /* sector number of bad sector */
  454.     
  455.     /* Find what file bad sector is allocated to */
  456.     if ((finfo = getstart(orphans, clno+2, ldev-'A')) == GORPH) {
  457.         markorph[ORPHYES].ob_state = NORMAL;
  458.         markorph[ORPHNO].ob_state = NORMAL;
  459.         (markorph[ORPHSEC].ob_spec)->te_ptext = sectbuf;
  460.     itoa(clno+2, clusbuf);    /* +2: 2 unused entries at FAT */
  461.         (markorph[ORPHCLU].ob_spec)->te_ptext = clusbuf;
  462.         if (execform(markorph) == ORPHYES) {    /* want to mark orphan */
  463.             *(fatimg+clno+2) = 0xf7ff;        /* 0xfff7 in 8086-land */
  464.             ret = 1;
  465.         } else {        /* don't want to mark orphan */
  466.             ret = 0;
  467.         }
  468.         goto leave;
  469.     } else if (finfo == GFAIL) {
  470.     ret = err(nomemory);
  471.     goto leave;
  472.     } /* else if (finfo == GALLO || finfo == GOOFY
  473.          If these are ever returned, it's this
  474.          program's fault.
  475.       */
  476.  
  477.     if (!(finfo->gs_fpath[0])) {    /* 0: can't read subdirectory */
  478.         err(sdirread);
  479.         ret = 0;
  480.         goto leave;
  481.     }
  482.         
  483.     /* root of full path name of file */
  484.     pname[0] = ldev;
  485.     pname[1] = ':';
  486.     pname[2] = '\0';
  487.  
  488.     /* Have to display entire path name */
  489.     strcat(pname, finfo->gs_fpath);
  490.     
  491.     /* Is trashed file a subdirectory? */
  492.     /* How many characters will the path name exceed width of dialogue? */
  493.     if ((attribs = Fattrib(pname, 0, 0)) & FA_SUB) {
  494.     sub = TRUE;
  495.     tail = (strlen(finfo->gs_fpath)+2)*gl_wchar-lmrksub[BADSUB].ob_width;
  496.     } else {
  497.     sub = FALSE;
  498.     tail = (strlen(finfo->gs_fpath)+2)*gl_wchar-lmrkfile[BADFILE].ob_width;
  499.     } 
  500.     
  501.     /* Display path name, sector & cluster # concerned */    
  502.     if (tail <= 0) {    /* path name of file will fit in dialogue */
  503.     strcpy(dpname, pname);
  504.     } else {        /* path name of file is too long for dialogue */
  505.     dpname[0] = ldev;
  506.     dpname[1] = ':';
  507.     dpname[2] = '\0';
  508.         strcat(dpname, "\\...");
  509.         strcat(dpname, &(finfo->gs_fpath[tail/gl_wchar+4]));
  510.     }
  511.     
  512.     /* Set up dialogue with info of trashed file/subdirectory */
  513.     if (sub == TRUE) {        /* it's a subdirectory file */
  514.         ret = marksub(ldev, fatimg, fatsiz, clno);
  515.     } else {            /* it's a regular file */
  516.         ret = markfile(ldev, fatimg, fatsiz, clno, nxtcl);
  517.     }
  518. leave:
  519.     return (ret);
  520. }                
  521.  
  522.  
  523. /*
  524.  *  Marksub()
  525.  *    Put up dialogue informing which subdirectory is trashed, and
  526.  *  request action from user.
  527.  *
  528.  *  Input:
  529.  *    ldev  - logical device number. ('C' -> 'P')
  530.  *    fatimg  - image of FAT 0.
  531.  *    fatsiz - size of FAT in sectors.
  532.  *    clno - cluster which bad sector resides.
  533.  *
  534.  *  Return:
  535.  *    1 - if successful and cluster with bad sector is marked.
  536.  *    0 - if successful but nothing marked.
  537.  *    ERROR - can't read boot sector.
  538.  *
  539.  *  Comments:
  540.  *    15-Apr-88 ml.  If user choose to delete the subdirectory, all
  541.  *  files and subdirectories belonging to that subdirectory will also
  542.  *  be deleted.
  543.  *    18-Apr-88 ml.  Try to implement recovering files so that the user
  544.  *  only lose the directory structure.  All files and subdirectories
  545.  *  belonging to the 'trouble maker' now become temporary files under
  546.  *  the root directory.  So, number of files recovered depends on number
  547.  *  of empty slots remained in the root directory.
  548.  * 
  549.  */
  550. marksub(ldev, fatimg, fatsiz, clno)
  551. int  ldev;
  552. UWORD *fatimg;
  553. UWORD fatsiz;
  554. UWORD clno;
  555. {
  556.     UWORD *neworphs;        /* list of new orphans */
  557.     int  *lstneworphs();
  558.     FCB  *dirent;        /* a directory entry */
  559.     UWORD clus, nxtcl;        /* current and next cluster number */
  560.     int  act;            /* action requested by user */
  561.     char buf[512];
  562.     int  ret = OK;
  563.     
  564.     lmrksub[BADSUB].ob_width = strlen(dpname)*gl_wchar; 
  565.     lmrksub[BADSUB].ob_x 
  566.     = (lmrksub->ob_width - lmrksub[BADSUB].ob_width) >> 1;
  567.     lmrksub[BADSUB].ob_spec = dpname;
  568.     (lmrksub[SUBSEC].ob_spec)->te_ptext = sectbuf;
  569.     itoa(clno+2, clusbuf);
  570.     (lmrksub[SUBCLU].ob_spec)->te_ptext = clusbuf;
  571.     
  572.     lmrksub[SUBDELSV].ob_state = NORMAL;
  573.     lmrksub[SUBDELNS].ob_state = NORMAL;
  574.     lmrksub[SUBIGNOR].ob_state = NORMAL;
  575.     
  576.     /* Put up the dialogue */
  577.     switch ((act = execform(lmrksub))) {
  578.     case SUBIGNOR:            /* clicked on ignore */
  579.         ret = 0;
  580.         goto subend;
  581.     
  582.     case SUBDELSV:            /* clicked on delete and save */
  583.         ARROW_MOUSE;
  584.         if (form_alert(2, svfiles) == 2) {    /* bail out */
  585.         BEE_MOUSE;
  586.         ret = 0;
  587.         goto subend;
  588.         }
  589.         break;
  590.         
  591.     case SUBDELNS:            /* clicked on delete and not save */
  592.         ARROW_MOUSE;
  593.         if (form_alert(2, nsfiles) == 2) {    /* bail out */
  594.         BEE_MOUSE;
  595.         ret = 0;
  596.         goto subend;
  597.         }
  598.         break;
  599.         
  600.     default:
  601.         break;
  602.     }    
  603.  
  604.     /* Really removing subdirectory and mark bad sector */
  605.     BEE_MOUSE;
  606.     /* Read directory sector containing the subdirectory file from disk */
  607.     if ((ret = rdsects(ldev, 1, buf, (SECTOR)finfo->gs_dsect)) != 0) {
  608.         if (tsterr(ret) != OK)
  609.         err(sdirread);
  610.     ret = 0;
  611.     goto subend;
  612.     }
  613.  
  614.     /* Get directory entry of file */
  615.     dirent = (FCB *)(buf + finfo->gs_doff);
  616.     
  617.     /* Delete the subdirectory */
  618.     dirent->f_name[0] = FN_DEL;
  619.     
  620.     /* Write directory sector containing the subdirectory file back to disk */
  621.     if ((ret = wrsects(ldev, 1, buf, (SECTOR)finfo->gs_dsect)) != 0) {
  622.         if (tsterr(ret) != OK)
  623.         err(sdirwrit);
  624.         ret = 0;
  625.     goto subend;
  626.     }
  627.  
  628.     /* Zero entries of the subdirectory file in FAT, and mark bad sector */
  629.                     /* start from beginning of file */
  630.     for (gw((UWORD *)&dirent->f_clust, &clus);
  631.          clus < 0xfff0;        /* until EOF or a cluster marked bad */
  632.          clus = nxtcl)        /* next cluster becomes current */
  633.     {
  634.          gw((UWORD *)(fatimg+clus), &nxtcl);  /* find where next cluster is */
  635.          *(fatimg+clus) = 0;             /* zero current cluster */
  636.     }
  637.     *(fatimg+clno+2) = 0xf7ff;        /* mark cluster with bad sector */
  638.     
  639.     /* Update FATs */
  640.     if ((ret = wrsects(ldev, fatsiz, (char *)fatimg, (SECTOR)1)) != 0 ||
  641.         (ret = wrsects(ldev, fatsiz, (char *)fatimg, (SECTOR)1+fatsiz)) != 0) {
  642.         if (tsterr(ret) != OK)
  643.         err(fatwrite);
  644.     ret = ERROR;
  645.     goto subend;
  646.     }
  647.  
  648.     /* Find out list of orphans introduced by deleting the subdirectory */
  649.     if ((neworphs = lstneworphs(ldev)) < 0) {
  650.         ret = ERROR;        /* error occurs when finding new orphans */
  651.         goto subend;
  652.     } else if (!neworphs) {
  653.         ret = 1;        /* No new orphans! No files to recover! */
  654.         goto subend;
  655.     }
  656.  
  657.     /* Recover files in subdirectory and put them in root directory */
  658.     if (act == SUBDELSV) {    /* requested to recover file */
  659.     if (rcvrfiles(ldev, fatimg, fatsiz, neworphs) != OK) {
  660.         ret = ERROR;
  661.         goto subend;
  662.     }
  663.     } else if (act == SUBDELNS) {    /* requested not to recover file */
  664.         if (rmvfiles(fatimg, neworphs) != OK) {
  665.             ret = ERROR;
  666.             goto subend;
  667.     }
  668.     }
  669.     ret = 1;        /* everything is fine.  JUST FINE... */
  670. subend:
  671.     if (neworphs > 0L) Mfree((long)neworphs);
  672.     return ret;
  673. }
  674.  
  675.  
  676.  
  677.  
  678. /*
  679.  *  Lstneworphs()
  680.  *    Find out what orphans exist and record them in an orphan list.
  681.  *
  682.  *  Input:
  683.  *    ldev - logical device number ('C' -> 'P')
  684.  *
  685.  *  Return:
  686.  *    neworphs - list of new orphans
  687.  *    0 - if there is no new orphans
  688.  *    ERROR - if anything goes wrong
  689.  */
  690. int*
  691. lstneworphs(ldev)
  692. int ldev;
  693. {
  694.     UWORD *neworphs;    /* current orphans in FAT */
  695.     UWORD *orphans;    /* current orphans in FAT */
  696.     int numnew, i;
  697.     long ret;
  698.     
  699.     /* Check integrity of FATs, and find all orphans that exist */
  700.     if ((orphans = fatck(ldev-'A')) <= 0L) {
  701.     switch (orphans) {
  702.         case FFATS:
  703.         ret = err(fatread);
  704.         goto lstend;
  705.         case FROOT:
  706.         ret = err(dirread);
  707.         goto lstend;
  708.         case FFAIL:
  709.         ret = err(nomemory);
  710.         goto lstend;
  711.         case FAMBI:
  712.         ret = err(badfat);
  713.         goto lstend;
  714.         default:
  715.         break;
  716.     }
  717.     }
  718.  
  719.     ret = 0L;    /* assume there is no new orphans */
  720.     
  721.     /* Any orphans in FAT? */
  722.     if (*orphans > 0) {        /* Yes, try to recover them */
  723.     /* Allocate space for new orphans */
  724.     if ((neworphs =
  725.         (UWORD *)Malloc((long)((*orphans+1)<<1))) <= 0L) {
  726.         ret = err(nomemory);
  727.         goto lstend;
  728.         }
  729.         
  730.     for (i = 0; i <= *orphans; i++)
  731.         *(neworphs + i) = *(orphans + i);
  732.         
  733.     ret = neworphs;
  734.     }
  735. lstend:
  736.     return ret;
  737. }
  738.  
  739.  
  740. /*
  741.  *  Rcvrfiles()
  742.  *    Recover files of a trashed subdirectory.  The files will
  743.  *  become temporary files in the root directory of the partition.
  744.  *  Their names will be tmpnnnn, where nnnn is a four digit hex
  745.  *  number which is the starting cluster number of that file.
  746.  *
  747.  *  Input:
  748.  *    ldev - logical device number. ('C' -> 'P')
  749.  *    fatimg  - image of FAT 0.
  750.  *    fatsiz - number of clusters FAT occupies.
  751.  *    neworphs - list of new orphans.
  752.  *
  753.  *  Output:
  754.  *    OK - recover (if necessary) is successful.
  755.  *    ERROR - something is wrong.
  756.  *
  757.  *  Comments:
  758.  *    To recover the new lost files, we construct a temporary FAT
  759.  *  which contains only the newly introduced orphans (excluding clusters
  760.  *  marked bad and reserved; that is, only if they are part of a file). 
  761.  *  All other entries are 0's.  We then walk through the FAT to find the
  762.  *  first non-zero entry, and call getstart() to find out where the head
  763.  *  of this chain is.  This chain will then be saved as a temp file in the
  764.  *  root directory, named tmpnnnn (nnnn is the starting cluster number of
  765.  *  the chain in hex).  To save the temp file in the root directory, we
  766.  *  have to search for an empty slot in the root and enter information of
  767.  *  the temp file into the directory entry.  After a chain is recovered,
  768.  *  zero out the chain in the temporary FAT and start to look for the next
  769.  *  non-zero entry in it for the next chain, until all chains are recovered.
  770.  *    Note that the content of the temporary FAT (referred to as fakefat)
  771.  *  is in regular 68000 word format.  The entries are _NOT_ in 8086 byte-
  772.  *  swapped format.
  773.  */    
  774. rcvrfiles(ldev, fatimg, fatsiz, neworphs)
  775. int ldev;
  776. UWORD *fatimg;
  777. UWORD fatsiz;
  778. UWORD *neworphs;
  779. {
  780.     FCB *rootdir, *availslot;    /* root directory; available slot */
  781.     GSINFO *chain;        /* info of an orphan chain of clusters */
  782.     UWORD *fakefat;        /* a temp fat image */
  783.     UWORD content;        /* cluster pointed to by a FAT entry */
  784.     UWORD orph2del;        /* number of orphan yet to be deleted */
  785.     UWORD i;            /* index into orphan list */
  786.     UWORD orph;            /* an orphan in fake FAT */
  787.     UWORD stfat;        /* index into fake FAT */
  788.     UWORD stdir;        /* index into root directory */
  789.     UWORD dirslot;        /* empty directory slot number */
  790.     UWORD numclus;        /* number of clusters file used */
  791.     UWORD prev, curr;        /* previous and current cluster number */
  792.     int done;            /* 1: finish recovering files */
  793.     int endofchain;        /* 1: reached end of file chain */
  794.     int rootfull;        /* root directory is full */
  795.     int tget;            /* current time or date */
  796.     int ret;            /* return code */
  797.     char namebuf[10];
  798.     
  799.     
  800.     /* Allocate space for root directory */
  801.     rootdir = 0L;
  802.     if ((rootdir = (FCB *)mymalloc(sectdir << 9)) <= 0L) {
  803.         ret = err(nomemory);
  804.         goto rcvrend;
  805.     }
  806.     
  807.     /* Read in root directory */
  808.     if ((ret = rdsects(ldev, sectdir, (char *)rootdir, strootdir)) != 0) {
  809.         if (tsterr(ret) != OK)
  810.             err(dirread);
  811.         ret = ERROR;
  812.         goto rcvrend;
  813.     }
  814.  
  815.     /* Allocate space for a temporary FAT image and zero it out */
  816.     fakefat = 0L;
  817.     if ((fakefat = (UWORD *)Malloc((long)fatsiz << 9)) <= 0L) {
  818.         ret = err(nomemory);
  819.         goto rcvrend;
  820.     }
  821.     fillbuf((char *)fakefat, ((long)fatsiz << 9), 0L);
  822.     
  823.     /* Copy the new orphans from current FAT to this       */
  824.     /* temporary FAT only if they are part of a file chain */
  825.     orph2del = 0;        /* no orphan is copied to fake FAT yet */
  826.     for (i = 1; i <= *neworphs; i++) {
  827.         gw((fatimg + *(neworphs + i)), &content);
  828.         if ((content >= 0x0002 && content <= 0x7fff)    /* part of file */
  829.             || (content >= 0xfff8 && content <= 0xffff)) {
  830.             *(fakefat + *(neworphs + i)) = content;    /* copy to temp FAT */
  831.             orph2del++;        /* one more orphan to take care of */
  832.         }
  833.     }
  834.  
  835.     /* start recovering... */
  836.     stfat = 2;            /* start at beginning of fake FAT */
  837.     stdir = 0;            /* start at beginning of root directory */
  838.     endofdir = FALSE;        /* not at end of root directory yet */
  839.     rootfull = 0;
  840.     
  841. nextorph:
  842.     while (orph2del > 0) {    /* more orphan to take care of? */
  843.         /* Yes, find next non-zero entry in fake FAT */
  844.         for (orph = stfat; *(fakefat+orph) == 0; orph++)
  845.             ;
  846.         stfat = orph + 1;    /* next time start from here to walk FAT */
  847.  
  848.     /* Root directory was already full, and user choose to 
  849.        deallocate all remaining new orphans on the disk.   */
  850.     if (rootfull) {            /* root directory is full already */
  851.         *(fatimg + orph) = 0;    /* deallocate orphan from real FAT */
  852.         orph2del--;            /* one fewer to go */
  853.         goto nextorph;        /* find the next one */
  854.     }
  855.     
  856.     /* Find an empty slot in the root directory */
  857.     if ((dirslot = rtdirslot(rootdir, stdir)) == ERROR) {
  858.         /* FIRST TIME -- Root directory is FULL! */
  859.         rootfull = 1;
  860.         if (execform(nodrslot) == NODRNO) {       /* wanna keep lost clus */
  861.             goto okend;               /* Nope! */
  862.         }
  863.         /* Yup. */
  864.         *(fatimg + orph) = 0;    /* Zero out current orphan */
  865.         orph2del--;            /* one fewer to go */
  866.         goto nextorph;        /* find the next one to zero out */
  867.     }
  868.     stdir = dirslot + 1; /* next time start from here to find slots */
  869.  
  870.     /* Find head of chain that this cluster belongs to */        
  871.     if ((chain = getstart(&emptyorph, orph, ldev-'A')) <= 0L) {
  872.         ret = ERROR;
  873.         goto rcvrend;
  874.     }
  875.  
  876.     /* Erase chain from fake FAT */
  877.     endofchain = 0;                /* not end of chain yet */
  878.     numclus = 0;                /* no cluster zeroed yet */
  879.     prev = curr = chain->gs_head;        /* start from head of chain */
  880.     
  881.     while (!endofchain) {            /* while not end of chain */
  882.         content = *(fakefat + curr);    /* next cluster in chain */
  883.         *(fakefat + curr) = 0;        /* zero current entry */
  884.         if (!content) {            /* next cluster is 0? */
  885.             endofchain = 1;            /* Yes, BAD! end it */
  886.             *(fatimg + prev) = 0xffff;    /* stop chain in real FAT */
  887.         } else if (content >= 0xfff8 && content <= 0xffff) { /* last clus */
  888.             numclus++;            /* zeroed last one */
  889.         endofchain = 1;            /* end of chain reached */
  890.         } else {                /* still at middle of chain */
  891.             prev = curr;            /* current becomes previous */
  892.         curr = content;            /* next becomes current */
  893.         numclus++;            /* one more is zeroed */
  894.         }
  895.     }
  896.     
  897.     /* Move the file to root directory and erase chain from fake FAT */
  898.     availslot = rootdir + dirslot;
  899.     strcpy(availslot->f_name, "TMP");          /* file name */
  900.     htoa((long)chain->gs_head, namebuf, 1);
  901.     strcat(availslot->f_name, namebuf);
  902.     strcat(availslot->f_name, "    ");
  903.     availslot->f_attrib = 0;              /* file attrib */
  904.     tget = Tgettime();                  /* time created */
  905.     iw(&(availslot->f_time), tget);
  906.     tget = Tgetdate();                  /* date created */
  907.     iw(&(availslot->f_date), tget);
  908.     iw(&(availslot->f_clust), chain->gs_head);      /* starting clus */
  909.     il(&(availslot->f_fileln), (long)(numclus*clusiz));  /* file length */
  910.     
  911.     /* update number of orphans to delete */
  912.     orph2del -= numclus;
  913.     }
  914.  
  915. okend:
  916.     /* Write root directory back on disk */
  917.     if ((ret = wrsects(ldev, sectdir, (char *)rootdir, strootdir)) != 0) {
  918.         if (tsterr(ret) != OK)
  919.               err(dirwrite);
  920.           ret = ERROR;
  921.         goto rcvrend;
  922.     }
  923.     ret = OK;
  924. rcvrend:
  925.     if (fakefat > 0) Mfree((long)fakefat);
  926.     if (rootdir > 0) free (rootdir);
  927.     return ret;
  928. }
  929.  
  930.  
  931. /*
  932.  *  Rtdirslot()
  933.  *    Find the next available directory slot in the root directory
  934.  *  of the given partition.
  935.  *
  936.  *  Input:
  937.  *    dirimg - image of the root directory read from disk.
  938.  *    start - directory slot number to start with.
  939.  *
  940.  *  Return:
  941.  *    dirslot - available directory slot number.
  942.  *    ERROR - no more available slot.
  943.  *
  944.  *  Comments:
  945.  *    Note that, a zero entry marks the end of the directory.  That is,
  946.  *  all subsequent entries are available.
  947.  */
  948. rtdirslot(dirimg, start)
  949. FCB *dirimg;
  950. int start;
  951. {
  952.     int i;
  953.     
  954.     if (endofdir == TRUE) {        /* End of directory reached? */
  955.         if (start < ndirs)        /* Yes, full? */
  956.             return (start);        /* No, next slot will be available. */
  957.         else                 /* Yes, no available slot */
  958.             return ERROR;
  959.     }
  960.         
  961.     for (i = start; i < ndirs; i++) {
  962.         if ((dirimg+i)->f_name[0] == FN_DEL) /* entry of a deleted file is OK */
  963.             return i;
  964.         if (!((dirimg + i)->f_name[0])) {    /* end of directory is reached */
  965.             endofdir = TRUE;
  966.             return i;
  967.         }
  968.     }
  969.     return ERROR;    /* no available slot found */
  970. }
  971.  
  972.  
  973. /*
  974.  *  Rmvfiles()
  975.  *    Remove orphan clusters which were allocated to files which
  976.  *  are now lost from the FAT.
  977.  *
  978.  *  Input:
  979.  *    fatimg  - image of FAT 0.
  980.  *    neworphs - list of new orphans.
  981.  *
  982.  *  Return:
  983.  *    OK - when finished.
  984.  */
  985. rmvfiles(fatimg, neworphs)
  986. UWORD *fatimg;
  987. UWORD *neworphs;
  988. {
  989.     int i;        /* index into orphan list */
  990.     UWORD content;    /* pointer to next cluster */
  991.     
  992.     for (i = 1; i <= *neworphs; i++) {
  993.         gw((fatimg + *(neworphs + i)), &content);
  994.         if ((content >= 0x0002 && content <= 0x7fff)    /* part of file */
  995.             || (content >= 0xfff8 && content <= 0xffff)) {
  996.         *(fatimg + *(neworphs + i)) = 0;        /* remove it */
  997.     }
  998.     }
  999.     return OK;
  1000. }
  1001.  
  1002. /*
  1003.  *  Markfile()
  1004.  *    Put up dialogue informing which file is trashed, and
  1005.  *  request action from user.
  1006.  *
  1007.  *  Input:
  1008.  *    ldev  - logical device number. ('C' -> 'P')
  1009.  *    fatimg  - image of FAT 0.
  1010.  *    fatsiz - number of clusters FAT occupies.
  1011.  *    clno - cluster which bad sector resides.
  1012.  *    nxtcl    - cluster pointed to by bad cluster.
  1013.  *
  1014.  *  Return:
  1015.  *    1 - if successful and cluster with bad sector is marked.
  1016.  *    0 - if successful but didn't mark the bad sector.
  1017.  *    ERROR - something's wrong.
  1018.  */
  1019. markfile(ldev, fatimg, fatsiz, clno, nxtcl)
  1020. int  ldev;
  1021. UWORD *fatimg;
  1022. UWORD fatsiz;
  1023. UWORD clno;
  1024. UWORD nxtcl;
  1025. {
  1026.     int  ret;
  1027.  
  1028.     lmrkfile[BADFILE].ob_width = strlen(dpname)*gl_wchar; 
  1029.     lmrkfile[BADFILE].ob_x 
  1030.     = (lmrkfile->ob_width - lmrkfile[BADFILE].ob_width) >> 1;
  1031.     lmrkfile[BADFILE].ob_spec = dpname;
  1032.     (lmrkfile[BADSEC].ob_spec)->te_ptext = sectbuf;
  1033.     itoa(clno+2, clusbuf);    
  1034.     (lmrkfile[BADCLU].ob_spec)->te_ptext = clusbuf;
  1035.     lmrkfile[DELFILE].ob_state = NORMAL;
  1036.     lmrkfile[SKIPOVER].ob_state = NORMAL;
  1037.     lmrkfile[IGNORBAD].ob_state = NORMAL;
  1038.  
  1039.     /* Put up the dialogue */
  1040.     ret = execform(lmrkfile);
  1041.  
  1042.     /* Action requested by Jackson is... */
  1043.     switch (ret) {
  1044.     case DELFILE:    /* Delete file */
  1045.         /* User's choice => can delete */
  1046.         if (Fdelete(pname)) {
  1047.         ret = err(cantdel);
  1048.         }
  1049.            
  1050.         /* Read current FAT; fat0 starts at sector 1 */
  1051.         if ((ret = rdsects(ldev, fatsiz, (char *)fatimg, (SECTOR)1)) != 0) {
  1052.             if (tsterr(ret) != OK)
  1053.             err(fatread);
  1054.         ret = ERROR;
  1055.         break;
  1056.         }
  1057.         
  1058.         /* Mark the cluster bad */
  1059.         *(fatimg+clno+2) = 0xf7ff;    /* 0xfff7 in 8086-land */
  1060.         ret = 1;    /* 1 cluster marked bad */
  1061.         break;
  1062.  
  1063.     case SKIPOVER:    /* Skip over bad sector */
  1064.         ret = skpfile(ldev, fatimg, fatsiz, clno, nxtcl);
  1065.         break;
  1066.  
  1067.     case IGNORBAD:
  1068.         ret = 0;
  1069.         break;
  1070.     
  1071.     default:
  1072.         ret = ERROR;
  1073.         break;
  1074.     }
  1075.     return ret;
  1076. }
  1077.  
  1078.  
  1079. /*
  1080.  *  Skpfile()
  1081.  *    Skip over a cluster which contains a bad sector of a file.
  1082.  *
  1083.  *  Input:
  1084.  *    ldev  - logical device number. ('C' -> 'P')
  1085.  *    fatimg  - image of FAT 0.
  1086.  *    fatsiz - number of clusters FAT occupies.
  1087.  *    clno - cluster which bad sector resides.
  1088.  *    nxtcl    - cluster pointed to by bad cluster.
  1089.  *
  1090.  *  Return:
  1091.  *    1 - if cluster with bad sector is marked.
  1092.  *    OK - if successful.
  1093.  *    ERROR - can't read boot sector.
  1094.  *
  1095.  *  Comments:
  1096.  *    Need to adjust length and/or modify directory entry of the
  1097.  *  corresponding file.
  1098.  *    Complications arise when file is a subdirectory.  For first
  1099.  *  trial, nothing is done for subdirectories for now.
  1100.  *
  1101.  */
  1102. skpfile(ldev, fatimg, fatsiz, clno, nxtcl)
  1103. int  ldev;
  1104. UWORD *fatimg;
  1105. UWORD fatsiz;
  1106. UWORD clno;
  1107. UWORD nxtcl;
  1108. {
  1109.     FCB  *dirent;        /* a directory entry */
  1110.     int  ret;            /* return code */
  1111.     long flen;            /* file length (68000 format) */
  1112.     long gl();            /* get a long from 8086 format */
  1113.     long left;            /* #bytes in last cluster of file */
  1114.     char buf[512];
  1115.     
  1116.     ret = OK;    /* assume everything is OK now... */
  1117.  
  1118.     /* Read directory sector containing the file from disk */
  1119.     if ((ret = rdsects(ldev, 1, buf, (SECTOR)finfo->gs_dsect)) != 0) {
  1120.         if (tsterr(ret) != OK)
  1121.         err(sdirread);
  1122.     ret = 0;
  1123.     goto skipend;
  1124.     }
  1125.  
  1126.     /* Get directory entry of file */
  1127.     dirent = (FCB *)(buf + finfo->gs_doff);
  1128.  
  1129.     /* Relink the file */
  1130.     if (!(finfo->gs_count - 1)) {    /* it's 1st cluster */
  1131.         if (nxtcl >= 0xfff0) {        /* it's also last cluster */
  1132.             if (Fdelete(pname))        /* just delete it */
  1133.                 ret = err(cantdel);
  1134.                 
  1135.             /* Read in current FAT; fat0 starts at sector 1 */
  1136.             if ((ret = rdsects(ldev, fatsiz, (char *)fatimg, (SECTOR)1)) != 0) {
  1137.                 if (tsterr(ret) != OK)
  1138.                     err(fatread);
  1139.                 ret = ERROR;
  1140.                 goto skipend;
  1141.             }
  1142.         goto markit;
  1143.         }
  1144.     iw(&(dirent->f_clust), nxtcl);    /* new starting clus = next clus */
  1145.     } else {            /* otherwise */
  1146.     iw((fatimg + finfo->gs_prev), nxtcl);  /* skip cluster marked bad */
  1147.     }
  1148.  
  1149.     /* Adjust file size */
  1150.     /* Is it end of file, or #bytes give exact clusters?? */
  1151.     gl(&(dirent->f_fileln), &flen);
  1152.     if (flen) {
  1153.     if ((!(left = flen % clusiz)) || nxtcl < 0xfff0)
  1154.         flen -= clusiz;    /* Yes, subtract entire unusable cluster */
  1155.     else
  1156.         flen -= left;    /* Nope, subtract unusable bytes */
  1157.     
  1158.     il(&(dirent->f_fileln), flen);    /* install new file length */
  1159.     }
  1160.  
  1161.     /* Write directory sector containing the file back to disk */
  1162.     if ((ret = wrsects(ldev, 1, buf, (SECTOR)finfo->gs_dsect)) != 0) {
  1163.         if (tsterr(ret) != OK)
  1164.         err(sdirwrit);
  1165.     ret = 0;
  1166.     goto skipend;
  1167.     }
  1168. markit:    
  1169.     /* Mark the cluster bad */
  1170.     *(fatimg+clno+2) = 0xf7ff;    /* 0xfff7 in 8086-land */
  1171.     ret = 1;    /* 1 cluster marked bad */
  1172. skipend:
  1173.     return (ret);
  1174. }
  1175.  
  1176.  
  1177. /*
  1178.  * Put long in memory in 8086 byte-reversed format.
  1179.  *
  1180.  */
  1181. il(d, s)
  1182. long *d;
  1183. long s;
  1184. {
  1185.     char *p;
  1186.  
  1187.     p = (char *)d;
  1188.     p[0] = s & 0xffff;
  1189.     p[1] = ((s >> 8) & 0xffff);
  1190.     p[2] = ((s >> 16) & 0xffff);
  1191.     p[3] = ((s >> 24) & 0xffff);
  1192. }
  1193.  
  1194.  
  1195. /*
  1196.  * Get word in memory, from 8086 byte-reversed format.
  1197.  *
  1198.  */
  1199. long gl(s, d)
  1200. long *s;
  1201. long *d;
  1202. {
  1203.     char *p, *q;
  1204.  
  1205.     p = (char *)s;
  1206.     q = (char *)d;
  1207.     q[0] = p[3];
  1208.     q[1] = p[2];
  1209.     q[2] = p[1];
  1210.     q[3] = p[0];
  1211.     return *d;
  1212. }
  1213.  
  1214.